﻿/**
 * nenglong.mvc.js
 * Library v0.0.2.1
 *
 * Copyright (c) 2003 - 2018, nenglong
 * All rights reserved.
 *
 * Date: 2013-06-30
 * 依赖于：nenglong.core.js
 */
$NL.defined("NengLong.Mvc", ["js/core/nenglong.util.js","js/lib/juicer-min.js"], function () {
    /**
     *mvc框架的全局配置,通过这个配置，将框架的实现与平台分离
     */
    $NL.cls("static Config", function () {
        //基础配置参数,由框架加载后进行附值，是mvc框架中所用到的文件路径等参数
        //平台类型，Admin：管理后台， YXT：翼校通中小学版， YUANXT：院校通，YOUER:幼儿版
        this.platformType = "";//NENGLONG_CMP_PLATFORMTYPE;
        //平台基础路径
        this.platformUrlBase = "";//this.urlBase + "/View/" + this.platformType
        //模板基础路径，即所有模板路径前面不变的那一段
        this.templateUrlBase = "";//this.urlBase + "/View/" + this.platformType + "/html/"
        //控件所在地址
        this.controlUrlBase = "";
        //接口文件
        this.httpInterfaceUrl = ""; //this.urlBase + "WebHttp/Action.ashx"
        //当前平台的登录接口地址
        this.httpLoginUrl = "";
        this.httpProxyUrl = "";
        this.loginRouteKey = "login";
        //拼装模板路径的方法，
        this.getTemplateFullUrl = function (url) {
            return this.templateUrlBase + url;
        }
        //拼装接口路径的方法
        this.getHttpInterfaceFullUrl = function (requestUrl, cmd, sid) {
            var url = !!requestUrl ? requestUrl : this.httpInterfaceUrl;
//            url += "?cmd=" + cmd;
//            if (NengLong.Mvc.Config.httpProxyUrl.length > 0) {
//                url = NengLong.Mvc.Config.httpProxyUrl + "&SessionId=" + sid + "&url=" + url;
//            }
            return url;
        }
        //控件模板地址
        this.getUserControlTemplatFullUrl = function (controlClassName) {
            if (controlClassName.indexOf("NengLong.Component.") == 0) {
                return this.controlUrlBase + controlClassName.replace("NengLong.Component.", "").replace(".View", "").split(".").join("/") + ".html";
            } else {
                return this.controlUrlBase.replace("/Component/", "") + controlClassName.replace("NengLong", "").replace(".View", "").split(".").join("/") + ".html";
            }
        }
        //通过模板url构建View类名，主要是用于view工厂中，通过url实例化view
        this.getViewClassNameByUrl = function (tUrl) {
            if (tUrl.indexOf(this.templateUrlBase) == 0) {
                tUrl = tUrl.replace(this.templateUrlBase, "");
            }
            //首字母转为大写（类定义中是大写的）
            var names = tUrl.replace(/\//g, ".").split(".");
            names.pop();//删除最后的html
            var r = $.map(names, function (n, i) {
                return n.charAt(0).toUpperCase() + n.substring(1, n.length);
            });
            return "NengLong." + this.platformType + "." + r.join(".") + ".View";
        }

        /*
         *模板引擎配置接口
         */
        //当前使用的引擎名称，通过这个配置，在页面render时适配当前的模板引擎
        this.currentTemplateEngine = "juicer";
        //引擎工厂
        this.templateEngine = {
            "juicer": {
                "compile": function (view, tpl) {
                    if (isUndefined(juicer)) {
                        $NL.log.e("需先加载juicer模板引擎文件");
                    }
                    view._compiledTpl = juicer(tpl);
                },
                "render": function (view, data) {
                    return view._compiledTpl.render(data);
                }
            }
        }
        //获取当前使用的引擎
        this.getTemplateEngine = function () {
            return this.templateEngine[this.currentTemplateEngine];
        }
        //添加引擎,通过该方法，可以为框架添加其它模板引擎
        this.addTemplateEngine = function (engineName, engine) {
            if (typeof (this.templateEngine[engineName]) == "undefined") {
                var en = {
                    "compile": function () {
                    }, "render": function () {
                        return ""
                    }
                };
                $.extend(en, engine);
                this.templateEngine[engineName] = en;
            }
            this.currentTemplateEngine = engineName;

        }
        //保持在线账号标志
        this.isKeepLoginState = false;
    });

    /**
     *mvc框架的Page操作类
     */
    $NL.cls("static Page", function () {
        this.history = [];//路由跳转的根节点view历史记录
        this.currentTopView = null;
        //全局事件设置
        this._event = {};
        this.eventSetup = function (setting) {
            this._event = $.extend(this._event, setting);
        };
        //监听url RouteKey变化
        $(document).ready(function () {
            $.ajaxSetup({
                //发送请求前触发
                beforeSend: function (xhr, settings) {
                    if (settings.dataType != "jsonp" && !!settings.isNLMvc) {
                        var view = getView();
                        if (!!view) {
                            xhr.view = view;
                            view._taskPush();
                        }
                    }
                },
                //完成请求后触发。即在success或error触发后触发
                complete: function (xhr, status) {
                    if (!!xhr.view) {
                        xhr.view._taskPop();
                    }
                }//,
//                success: function (evt, request, xhr) {
//                    if (xhr.view != null) {
//                        xhr.view._taskPop();
//                    }
//                },
//                error: function (xhr, textStatus, errorThrown) {
//                    if (xhr.view != null) {
//                        xhr.view._taskPop();
//                    }
//                }
            });
            function getView() {
                var caller = getView.caller;
                while (caller != null && isUndefined(caller.__self)) {
                    caller = caller.caller;
                }

                return caller != null ? caller.__self : null;
            }

//            $(document).on("click", "a", function () {
//                setTimeout(function () {
//                    var k = NengLong.Mvc.Route.getRouteKey();
//                    if (k != null && k != NengLong.Mvc.Route.currentRouteKey) {
//                        NengLong.Mvc.Page.navigate(k);
//                    }
//                }, 0.5);
//            });
        });
        //根据路由key进行跳转页面
        this.navigate = function (routeKey, sid) {
            NengLong.Mvc.Route.setLocationUrl(routeKey);
            if (!!sid) NengLong.Util.Cookie.setCookie("jxpt_sessionid", sid);
            var self = this;
            $NL.script.loadScripts(NengLong.Mvc.Route.getRelpFiles(), function () {
                var rootInfo = NengLong.Mvc.Route.getRouteRoot();
                self.currentTopView = new viewFactory($("#" + rootInfo.id), rootInfo.url);
                self.currentTopView._eventOrderControl();//preRender();
                self.history.push(self.currentTopView);
            });
        }
        //加载子模板,支持以下三种重载
        //loadTemplate($container, url);
        //loadTemplate($container, url, params);
        //loadTemplate($container, url, parentView);
        //loadTemplate($container, url, parentView,htmlTemplate); add by gzq
        this.loadTemplate = function () {
            //loadTemplate($container, url);
            var $container = arguments[0], url = arguments[1], parentView = null, params = null;
            var htmlTemplate = null;
            var view = $container.data("view");

            if (arguments.length >= 3) {
                if (isUndefined(arguments[2]))
                    params = arguments[2];//loadTemplate($container, url, parentView);
                else
                    parentView = arguments[2];//loadTemplate($container, url, params);
            }
            if (arguments.length == 4) htmlTemplate = arguments[3];

            //view不为空时，parentView以view的_parentView为准，不以传入的参数为准
            if (!isUndefined(view)) {
                if (parentView != null && parentView != view._parentView)
                    $NL.log.w("loadTemplate传入的parentView与通过$container找到的view指向的parentView不一致");
                parentView = view._parentView;
                //路径有变化时创建新的view
                if (view._templateUrl != url) {
                    deleteChildView(parentView, $container[0]);
                    view = new viewFactory($container, url, parentView, htmlTemplate);
                }
            }
            else {
                if (parentView != null) {
                    view = new viewFactory($container, url, parentView, htmlTemplate);

                }
                else {
                    $NL.log.e("loadTemplate找不到对象加载的view，并且parentView为null");
                    return;
                }
            }
            if ($.isPlainObject(params))
                $.extend(view.params, params);
            NengLong.Mvc.Page._viewMvcControlPropertyBind(view, $container, "property");
            NengLong.Mvc.Page._viewMvcControlPropertyBind(view, $container, "initconfig");
            view._eventOrderControl();
            return view;
        }

        //刷新页面或view，支持以下重载
        //refresh()
        //refresh(params)
        //refresh($container)
        //refresh($container, params);
        this.refresh = function () {
            var view = this.currentTopView;
            if (arguments.length >= 1 && !$.isPlainObject(arguments[0])) {
                var $container = arguments[0];
                if (!isUndefined($container)) {
                    view = $container.data("view");//findView(view._childrenViews, $container[0]);
                    if (view == null) {
                        $NL.log.e("找不到对象加载的view，对象id为" + $container.attr("id"));
                        return;
                    }
                }
            }
            if ($.isPlainObject(arguments[0])) {
                $.extend(view.params, arguments[0]);
            }
            else if ($.isPlainObject(arguments[1])) {
                $.extend(view.params, arguments[1]);
            }

            view.refresh();

        }
        //用于扩展,大写是为了与类名调用保持一致
        this.Extend = {
            "viewBase": {},
            "viewExtend": function (name, action) {
                NengLong.Mvc.Page.Extend.viewBase[name] = action;
            },
            "modelBase": {},
            "modelExtend": function (name, action) {
                NengLong.Mvc.Page.Extend.modelBase[name] = action;
            }

        }

        //唯一id创建器
        var __id = 0;
        this._createId = function () {
            __id++;
            return "nl" + __id;
        }

        this._liftEventOrderCtrl = function (view) {
            if (view._processState == 2 && view._viewState < 5) {
                var childAllReady = eachChildrens(function (_this) {
                    return _this._processState == 2
                });
                if (childAllReady) {
                    if (view._parentView == null || view._parentView._viewState == 5) {
                        view._viewState++;
                        view._processState = 0;
                        view._eventOrderControl();
                    }
                    else {
                        view._parentView._eventOrderControl();
                    }
                    return;
                }
            }
            if (view._processState == 0 && view._viewState >= 0 && view._viewState <= 5) {
                view._taskPush();
                if (view._viewState == 0) {
                    view._preInit.__self = view;
                    view._preInit();
                }
                else if (view._viewState == 1) {
                    if (view._parentView == null || view._parentView._viewState == 5) {
                        if (!isUndefined(this._event.init)) this._event.init();
                    }
                    view.init.__self = view;
                    view.init();
                    eachChildrens(function (_this) {
                        _this._viewState = 1;
                        _this._processState = 0;
                        _this._eventOrderControl();
                        return true
                    });
                }
                else if (view._viewState == 2) {
                    view.render.__self = view;
                    view.render();
                    eachChildrens(function (_this) {
                        _this._viewState = 2;
                        _this._processState = 0;
                        _this._eventOrderControl();
                        return true
                    });
                }
                else if (view._viewState == 3) {
                    view._databind.__self = view;
                    view._databind();
                    eachChildrens(function (_this) {
                        _this._viewState = 3;
                        _this._processState = 0;
                        _this._eventOrderControl();
                        return true
                    });
                }
                else if (view._viewState == 4) {
                    view._unload.__self = view;
                    view._unload();
                    eachChildrens(function (_this) {
                        _this._viewState = 4;
                        _this._processState = 0;
                        _this._eventOrderControl();
                        return true;
                    });
                }
                else if (view._viewState == 5) {
                    view.finish.__self = view;
                    eachChildrens(function (_this) {
                        _this._viewState = 5;
                        _this._processState = 0;
                        _this._eventOrderControl();
                        return true
                    });
                    $.each(view._childrenViews, function (k, v) {
                        v._eventOrderControl();
                    });
                    view.finish();
                    if (view._parentView == null || view._parentView._viewState == 5) {
                        if (!isUndefined(this._event.finish)) this._event.finish();
                    }
                }
                view._taskPop();
                //模拟异步，让主线程先执行完
//                $NL.log.w(view.className);
//                $NL.log.w(view.base.className);
//                if(!!view && ((view.className=="NengLong.Mvc.Control" ||view.className=="NengLong.Mvc.UserControl") ||
//                    (!!view.base && (view.base.className=="NengLong.Mvc.Control" ||view.base.className=="NengLong.Mvc.UserControl")))){
//                    view._taskPop();
//                }else{
//                    setTimeout(function () {
//                        view._taskPop();
//                    }, 0);
//                }
            }
            function eachChildrens(fun) {
                //遍历全部
                var eachAll = true;
//                if (!isUndefined(view._childrenViews)) {
//                    $.each(view._childrenViews, function () {
//                        eachAll = fun(this);
//                        return eachAll;
//                    });
//                }
                if (eachAll && !isUndefined(view.userControl)) {
                    $.each(view.userControl, function () {
                        eachAll = fun(this);
                        return eachAll;
                    });
                }
                if (eachAll && !isUndefined(view.control)) {
                    $.each(view.control, function () {
                        eachAll = fun(this);
                        return eachAll;
                    });
                }
                return eachAll;
            }
        }
        /**
         * 实例化view的控件树（包括子view）;
         * @param view 容器对象
         * @param html 模板代码
         */
        this._controlTreeInit = function (view, html) {
            html = html.replace(/data-include/gi, "#replace#-include");
            html = html.replace(/data-control/gi, "#replace#-control");
            html = html.replace(/data-userControl/gi, "#replace#-userControl");
            while (html.indexOf("#replace#-") > 0) {
                html = html.replace(/#replace#-include/i, 'data-mvcid="' + this._createId() + '" data-include');
                html = html.replace(/#replace#-control/i, 'data-mvcid="' + this._createId() + '" data-control');
                html = html.replace(/#replace#-userControl/i, 'data-mvcid="' + this._createId() + '" data-userControl');
            }
            NengLong.Mvc.Config.getTemplateEngine().compile(view, html);
            var $c = $("<div>" + NengLong.Mvc.Config.getTemplateEngine().render(view, null) + "</div>");
            $c.find("[data-include]").each(function () {
                var id = $(this).attr("id");
                var mvcId = $(this).attr("data-mvcid");
                var templateUrl = NengLong.Mvc.Route.getRouteTemplates()[id];
                if (typeof (templateUrl) == "undefined") {
                    templateUrl = $(this).attr("data-include");
                }
                NengLong.Mvc.Page.loadTemplate($(this), templateUrl, view)._mvcId = mvcId;
            });
            $c.find("[data-control]").each(function () {
                var controlName = $.trim($(this).attr("data-control"));
                if (controlName.indexOf("NengLong") != 0) {
                    controlName = "NengLong.Component.Control." + controlName;
                }
                var mvcId = $(this).attr("data-mvcid");
                var id = $(this).attr("id") || $(this).attr("data-id");
                var control = $NL.cls(controlName);
                if (control == null) {
                    $NL.log.e(controlName + " 控件不存在。");
                }
                else {
                    control._mvcId = mvcId;
                    if (!isUndefined(id)) {
                        view.control[id] = control;
                    }
                    else {
                        view.control[mvcId] = control;
                    }

                    control.containHtml = $(this).clone();
                    control._parentView = view;
                    NengLong.Mvc.Page._viewMvcControlTmplScriptBind(control, $(this));
                    NengLong.Mvc.Page._viewMvcControlPropertyBind(control, $(this), "property");
                    NengLong.Mvc.Page._viewMvcControlPropertyBind(control, $(this), "initconfig");
                    control._eventOrderControl();
                }
            });
            $c.find("[data-userControl]").each(function () {
                var controlName = $.trim($(this).attr("data-userControl"));
                if (controlName.indexOf("NengLong") != 0) {
                    controlName = "NengLong.Component.UserControl." + controlName;
                }
                controlName += ".View";
                var id = $(this).attr("id") || $(this).attr("data-id");
                var mvcId = $(this).attr("data-mvcid");
                var userControl = $NL.cls(controlName);
                if (userControl == null) {
                    $NL.log.e(controlName + " 控件不存在。");
                }
                else {
                    userControl._mvcId = mvcId;
                    userControl.data = view.getControlData($(this));
                    var modelClassName = controlName.replace(".View", ".Model");
                    var model = $NL.cls(modelClassName);
                    userControl.model = model;
                    if (!isUndefined(id)) {
                        view.userControl[id] = userControl;
                    }
                    else {
                        view.userControl[mvcId] = userControl;
                    }
                    userControl.containHtml = $(this).clone();
                    userControl._parentView = view;
                    NengLong.Mvc.Page._viewMvcControlTmplScriptBind(userControl, $(this));
                    NengLong.Mvc.Page._viewMvcControlPropertyBind(userControl, $(this), "property");
                    NengLong.Mvc.Page._viewMvcControlPropertyBind(userControl, $(this), "initconfig");
                    userControl._eventOrderControl();
                }
            });
        }

        this._setControlTreeContainer = function (view) {
            this._viewControlBind(view);
            if (!isUndefined(view._childrenViews)) {
                $.each(view._childrenViews, function () {
                    this.set$C(view.get$C().find("[data-mvcId=" + this._mvcId + "]"));
                });
            }
            if (!isUndefined(view.userControl)) {
                $.each(view.userControl, function () {
                    this.set$C(view.get$C().find("[data-mvcId=" + this._mvcId + "]"));
                });
            }
            if (!isUndefined(view.control)) {
                $.each(view.control, function () {
                    this.set$C(view.get$C().find("[data-mvcId=" + this._mvcId + "]"));
                });
            }
        }
        /**
         * 绑定view中有id的jquery 对象到this.$中，可以使用this.$.id访问该对象，相当于$("#id");
         * @param view 容器对象
         * @param target 指定的jquery对象下子节点到view上，如target为空，则绑定view下的节点到view
         */
        this._viewControlBind = function (view, target) {
            var self = target || view.get$C();
            self.attr("parentClassName", view.className);
            self.find("[id],[data-id],[data-event]").each(function () {
                var $control = $(this);
                //在这里将有事件的控制添加所在view的className,在绑定事件时需要判断触发事件的控制是否属于这个view,为了解决view嵌套时，内层的事件寻址到外层view的方法中
                var viewClassName = view.className;
                $control.attr("viewClassName", viewClassName);
                var id = $control.attr("id") || $control.attr("data-id");
                view.$[id] = $control;
            });
        }

        this._viewMvcGetControlData = function ($control) {
            var param = null;
            try {
                var v = $control.attr("data-data");
                if (!isUndefined(v)) {
                    eval("param = " + v);
                }
            }
            catch (err) {
                $NL.log.e(err + " --绑定控件数据出错！");
                param = {};
            }
            return param;
        }

        /**
         *view的事件绑定,由于view的事件绑定在用户控件及view的基类都用到，故提取到page中，_viewEventBind的生命周期在_viewControlBind后面
         * @param view 容器对象
         * @param target 指定的jquery对象下的[data-event]到view上，如target为空，则绑定view下的[data-event]到view
         */
        this._viewEventBind = function (view, target) {
            var self = target || view.get$C();
            self.find("[data-event]").each(function () {
                if (view.className == $(this).attr("viewClassName")) {
                    var de = $(this).attr("data-event");
                    var data = getTargetEventData($(this));
                    var evs = de.split(";");
                    for (var i = 0; i < evs.length; i++) {
                        var ev = evs[i];
                        var l = ev.split(",");
                        var eName = l[0], funName = l[l.length - 1];
                        var _this = this;
                        //对于切割后大于3的，第一个为事件名，最后一个为对应的方法，中间的组合为选择器
                        if ((eName == "keydown" || eName == "keypress" || eName == "keyup")
                            && (this.tagName.toLowerCase() != 'textarea')
                            && (this.tagName.toLowerCase() != 'input' || (this.tagName.toLowerCase() == 'input' && $(this).attr("type") == 'button'))) {
                            var nleid = NengLong.Mvc.Page._createId();
                            //因为事件绑定到document,所以要对原对象加以标识
                            $(this).attr("nleid", nleid);
                            _this = document;
                        }
                        if (l.length >= 3) {
                            var ef = {};
                            ef["_fun_" + eName] = view[funName];
                            ef["_target$"] = this;
                            $.extend(data, ef);
                            var selector = l.slice(1, l.length - 1).join(",");
                            $(_this).off(eName, selector, eventProxy).on(eName, selector, data, eventProxy);
                        }
                        else if (l.length == 2) {
                            var ef = {};
                            ef["_fun_" + eName] = view[funName];
                            ef["_target$"] = this;
                            $.extend(data, ef);
                            $(_this).off(eName, eventProxy).on(eName, data, eventProxy);
                        }
                        else {
                            $NL.log.e(this.className + "事件绑定出错，事件参数：" + ev);
                        }
                    }
                }
            });
            //$NL.log.d(this.className + " bindEvent");
            function eventProxy(event) {
                var data = getTargetEventData($(this));
                $.extend(event.data, data);
                event.view = view;//记录调用事件的view
                //this是触发事件的dom元素。
                var _target = event.data["_target$"];
                if (!!_target && (event.type == "keydown" || event.type == "keypress" || event.type == "keyup")
                    && (_target.tagName.toLowerCase() != 'textarea')
                    && (_target.tagName.toLowerCase() != 'input' || (_target.tagName.toLowerCase() == 'input' && $(_target).attr("type") == 'button'))) {

                    //因为事件绑定到document,所以要对原对象用特定标识来判断原对象是否存在，如果不存在就取消事件
                    if ($("[nleid=" + $(_target).attr("nleid") + "]").length <= 0) {
                        $(document).off(event.type);
                        return;
                    }
                }
                event.data["_fun_" + event.type].call(view, event, this);
            }

            //获取事件触发者绑定在data-data中的参数
            function getTargetEventData($sender) {
                var data = $.trim($sender.attr("data-data"));
                if (typeof (data) != "undefined") {
                    if (data.indexOf("{") == 0)
                        try {
                            eval("data=" + data);
                        }
                        catch (err) {
                            $NL.log.e(view._templateUrl + " 页面的data参数格式出错" + data);
                            data = { "default": data };
                        }
                    else
                        data = { "default": data };
                }
                return data || {};
            }
        }

        /**
         * 绑定配置属性property
         * @param view
         * @param $c 容器
         * @param propertyName 绑定的属性名，如property表示data-property-
         * @private
         */
        this._viewMvcControlPropertyBind = function (view, $c, propertyName) {
            propertyName = $.trim(propertyName);
            if ($c.length > 0 && !!propertyName) {
                var c = $c.get(0);
                var prev = "data-" + propertyName + "-";
                var deleteAttr = [];
                for (var i = 0; i < c.attributes.length; i++) {
                    var name = c.attributes[i].nodeName;
                    var value = c.attributes[i].nodeValue;
                    if (name.indexOf(prev) > -1) {
                        deleteAttr.push(name);
                        var arr = name.substr(prev.length).split('-');
                        if (!view[propertyName]) view[propertyName] = {};
                        var confAttr = view[propertyName];
                        for (var j = 0; j < arr.length; j++) {
                            var propName = arr[j].toLocaleLowerCase();//将data-initconfig-propName中的propName转到小写 modify by lyn 2013-12-12
                            if (j < arr.length - 1) {
                                if (!confAttr[propName]) confAttr[propName] = {};
                                confAttr = confAttr[propName];
                            } else {
                                if (value.toLowerCase() === "true") {
                                    confAttr[propName] = true;
                                } else if (value.toLowerCase() === "false") {
                                    confAttr[propName] = false;
                                } else if ($.isNumeric(value)) {
                                    confAttr[propName] = parseFloat(value);
                                }
                                else {
                                    confAttr[propName] = value;
                                }
                            }
                        }
                    }
                }
                for (var i = 0; i < deleteAttr.length; i++) {
                    $(c).removeAttr(deleteAttr[i]);
                }
            }
        }

        //绑定自定义模板嵌套脚本块
        //<script type="text/tmpl"></script>
        //$c容器
        this._viewMvcControlTmplScriptBind = function (view, $c) {
            view.tmplScript = [];
            $c.find("script[type=text\\/tmpl]").each(function () {
                var $s = $('<div>' + $(this).html() + '</div>');
                $s.find("[data-mvcid]").removeAttr("data-mvcid");
                var t = $s.html().replace(new RegExp("@@", "gm"), "@").replace(new RegExp("\\$@", "gm"), "$");
                var script = $('<div></div>').append(this).html();
                script = script.replace(/>.*<\/script>/gi, '>' + t + '</script>');
                view.tmplScript.push($(script)[0]);
            });
        }

        //查找jquery对象
        this._find$ = function (view, tagId) {
            var f = view.get$C().find('[data-id=' + tagId + ']');
            if (f.length > 0)
                return f.first();
            else {
                f = view.get$C().find('#' + tagId + '');
                if (f.length > 0) {
                    return f.first();
                }
            }
            return null;
        }

        //显示view树,用于调试
        this.showViewTree = function () {
            $NL.log.i(this.currentTopView._templateUrl);
            showViewChild(this.currentTopView);
            function showViewChild(view) {
                for (var i = 0; i < view._childrenViews.length; i++) {
                    $NL.log.i(view.className + " ---- " + view._childrenViews[i]._templateUrl);
                    showViewChild(view._childrenViews[i]);
                }
            }

            return "==showViewTree调试==";
        }
        //通过容器的dom元素,删除view中childrenViews对应的view,并返回删除的对象。
        function deleteChildView(view, container) {
            for (var i = 0; i < view._childrenViews.length; i++) {
                if (view._childrenViews[i].get$C()[0] == container) {
                    //删除元素并返回删除的元素
                    return view._childrenViews.splice(i, 1)[0];
                }
            }
            return null;
        }

        //view创建工厂
        function viewFactory($container, htmlUrl, parentView, htmlTemplate) {
            var view = this.create(htmlUrl);
            view._templateUrl = htmlUrl;
            if (!!htmlTemplate) {
                view.templateHtml = htmlTemplate;
                NengLong.Mvc.Config.getTemplateEngine().compile(view, htmlTemplate);
            }

            if ($container.length == 0) {
                $NL.log.e(htmlUrl + "的容器对象不存在。");
                return null;
            }

            if (!isUndefined(parentView)) {
                view._parentView = parentView;
                parentView._childrenViews.push(view);
            }
            view.set$C($container);
            var mvcid = $container.attr("data-mvcid");
            var id = $container.attr("id"), dataId = $container.attr("data-id");
            if (!isUndefined(id)) view._viewId = id;
            else if (!isUndefined(dataId)) view._viewId = dataId;
            else if (!isUndefined(mvcid)) view._viewId = mvcid;
            return view;
        }

        viewFactory.prototype.create = function (htmlUrl) {
            var viewClassName = !!htmlUrl ? NengLong.Mvc.Config.getViewClassNameByUrl(htmlUrl) : null;
            var view = !!viewClassName ? $NL.cls(viewClassName) : null;
            if (view == null) {
                $NL.log.i(viewClassName + " view不存在，实例化基类。");
                view = new NengLong.Mvc.View();
            }
            var modelClassName = !!viewClassName ? viewClassName.replace(".View", ".Model") : null;
            var model = !!modelClassName ? $NL.cls(modelClassName) : new NengLong.Mvc.Model();
            if (model != null)
                view.model = model;
            return view;
        }
    });

    /**
     *mvc框架的Route路由控制类，静态类，不能实例化，提供静态函数
     */
    $NL.cls("static Route", function () {
        this._routeCache = {};//路由节点合局缓存
        this._relpFilesCache = {};//路由依赖的脚本文件
        this._default = {
            "root": { "id": "", "url": "" }, //根配置，根据根配置加载第一个view
            "templates": {}, //优先加载模板，模板中的include加载的子模板,如<a id="head" data-include="head.html"></a>则a节点加载的模板，首先查找templates[head]，不存在才加载head.html;
            "params": {},//路由参数
            "cssClass": {}
        };
        this.currentRouteKey = null; //当前的RouteKey
        //第一个参数是路由节点，第二个参数是依赖jsmap中的对应key的节点
        this.add = function (obj, jsmapKeys) {
            var rJs = []; //依赖的脚本文件
            for (var i = 0; i < jsmapKeys.length; i++) {
                var jsmap = $NL.script.getMapByKey(jsmapKeys[i]);
                if (jsmap != null) {
                    for (var j = 0; j < jsmap.src.length; j++) {
                        rJs.push(jsmap.src[j].url);
                    }
                }
            }
            var self = this;
            $.each(obj, function (key, val) {
                self._relpFilesCache[key] = rJs;
            });
            $.extend(this._routeCache, obj);
        }

        //通过当前路径的k参数，获取当前路由依赖的脚本文件列表
        this.getRelpFiles = function () {
            var routeKey = NengLong.Util.Url.getQueryParam("k");
            var jss = this._relpFilesCache[routeKey];
            if (typeof (jss) == "undefined")
                jss = [];
            return jss;
        }
        this.getRouteKey = function () {
            var k = NengLong.Util.Url.getQueryParam("k");
            if (k == null)
                k = this.currentRouteKey;
            var sid = NengLong.Util.Url.getQueryParam("SessionId");
            if (!!sid) {
                NengLong.Util.Cookie.setCookie("jxpt_sessionid", sid);
            }
            return k;
        }
        //通过当前路径的k参数，获取路由节点
        this.getRoute = function () {
            var routeKey = this.getRouteKey();
            if (!$.isPlainObject(this._routeCache[routeKey])) {
                $NL.log.e("找不到路由，routeKey:" + routeKey);
                return this._default;
            }
            var re = {};
            $.extend(re, this._default, this._routeCache[routeKey]);
            return re;
        }
        //通过当前路径的k参数，获取路由的根配置
        this.getRouteRoot = function () {
            return this.getRoute().root;
        }
        //通过当前路径的k参数，获取路由的模板配置列表，
        this.getRouteTemplates = function () {
            return this.getRoute().templates;
        }
        //通过当前路径的k参数，获取路由的参数配置
        this.getRouteParams = function () {
            return this.getRoute().params;
        }

        //通过当前路径的k参数，获取路由的参数配置
        this.getRouteCssClass = function () {
            return this.getRoute().cssClass;
        }
        //根据routeKey,设置当前的路径成为url#k=route这种形式，从页通过链接的参数进行页面跳转，并支持浏览器的后退前进刷新等。
        this.setLocationUrl = function (routeKey) {
            this.currentRouteKey = routeKey;
            window.location.href = NengLong.Util.Url.createUrl({ k: routeKey });
        }
    });

    /**
     *mvc框架的Model基类，提供给具体的项目的Model继承
     */
    $NL.cls("Model", function () {
        $.extend(this, NengLong.Mvc.Page.Extend.modelBase);
        this._default = {};
        this.find = function () {
            return NengLong.Util.Array.find.apply(this, arguments);
        }
        //requestUrl可选 
        this.request = function (params, callback, requestUrl) {
            var url = NengLong.Mvc.Config.getHttpInterfaceFullUrl(requestUrl);
            $.ajax({
                type: "post",
                dataType: "json",
                isNLMvc: true,
                url: "proxy.php",
                data: "url="+url+"&request="+string.fromObj(params),
                success: function (data) {
                    var mObj = null;
                    var msg = "";
                    if (!!data.Msg && data.state != 1) {
                        mObj = JSON.parse(data.Msg);
                        for (var i = 0; i < mObj.length; i++) {
                            msg += mObj[i].Message + "\n";
                        }
                    }
                    switch (data.state) {
                        case 1:
                            if ($.isFunction(callback)) {
                                callback(data);
                            }
                            break;
                        case 101:
                            NengLong.Util.alert(msg, "信息提示", function () {
                                NengLong.Mvc.Page.navigate(NengLong.Mvc.Config.loginRouteKey);
                            });
                            break;
                        case 102:
                        case 103:
                        case 104:
                        case 999:
                            NengLong.Util.alert(msg);
                            break;
                        default:
                            $NL.log.i(string.fromObj(data));
                            break;
                    }
                },
                error: function (rs) {
                    if (rs.status != 0) {
                        NengLong.Mvc.Page.navigate(NengLong.Mvc.Config.loginRouteKey);
                    }
                }
            });
        }

    });

    /**
     *mvc框架的View基类，提供给具体的项目的View继承
     */
    $NL.cls("View", function () {
        $.extend(this, NengLong.Mvc.Page.Extend.viewBase);
        //公有变量或访问器
        this.model = new NengLong.Mvc.Model;
        this.params = NengLong.Mvc.Route.getRouteParams();
        this.cssClass = NengLong.Mvc.Route.getRouteCssClass();
        this.control = {};//view中的mvc控件集合
        this.userControl = {};//view中的用户控件集合
        this.property = {};//Control中的配置属性property集合 add by gzq
        this.initconfig = {};//Control中的配置属性initconfig集合,约定只能用控件init初始化时使用，其他时刻禁用 add by gzq
        this.$ = {};//view中的jquery控件集合
        this.page = NengLong.Mvc.Page;
        this.set$C = function ($container) {
            this._$container = $container;
            this._$container.data("view", this);
            this._viewId = $container.attr("data-viewId");
        }
        this.get$C = function () {
            return this._$container;
        }
        this.datasource = null;
        this.getParentView = function () {
            return this._parentView;
        }
        this.getChildrenView = function (viewId) {
            if (!!viewId) {
                for (var i = 0; i < this._childrenViews.length; i++) {
                    if (this._childrenViews[i]._viewId == viewId) return this._childrenViews[i];
                }
            } else {
                if (this._childrenViews.length > 0)
                    return  this._childrenViews[0];
            }

            return null
        }

        //私有变量
        this._$container = null;//容器，即模板填充的jquery对象
        this._templateUrl = "";//模板地址
        this.templateHtml = "";
        this._compiledTpl = null;//编译后的模板
        this._viewState = 0; //0初始化(PreInit) 1 (Init)， 2(render) 3(databind) 4(finish) 5（unload）（加载完成）
        this._processState = 0; //0等待， 1处理中，2处理完成，等待下一步。
        this.__taskCount = 0; //正在处理的任务数量计数器
        this._parentView = null;//父view
        this._childrenViews = [];//子view列表
        this._hidden;//是否隐藏
        this._viewId = null;//系统产生的唯一id


        //加载过度动画
        this._loadAnimate = function (isLoaded) {
            if (isUndefined(this._hidden)) {
                if (isLoaded) {
                    this.get$C().fadeIn("slow");
                } else {
                    this.get$C().hide();
                }
            }
        }

        //构造函数
        this.View = function () {

        }

        this._taskPush = function () {
            if (this.__taskCount == 0) {
                this._processState = 1;
            }
            this.__taskCount++;
            $NL.log.i(this.className + " 的__taskCount+1 = " + this.__taskCount + ", viewState = " + this._viewState);
        }
        this._taskPop = function () {
            this.__taskCount--;

            $NL.log.i(this.className + " 的__taskCount-1 = " + this.__taskCount + ", viewState = " + this._viewState);
            if (this.__taskCount == 0) {
                var self = this;
                if (this._parentView == null || this._parentView._viewState == 5) {
                    setTimeout(function () {
                        self._processState = 2;
                        self._eventOrderControl();
                    }, 0);
                }
                else {
                    setTimeout(function () {
                        self._processState = 2;
                        self._parentView._eventOrderControl();
                    }, 0);
                }
            }
        }

        //生命周期事件控制
        this._eventOrderControl = function () {
            NengLong.Mvc.Page._liftEventOrderCtrl(this);
        }
        //不能重载
        this._preInit = function () {
            $.each(this.cssClass, function (htmlId, cssClass) {
                var $q = $("#" + htmlId) || $("[data-id=" + htmlId + "]");
                if ($q.length > 0 && !$q.hasClass(cssClass)) {
                    $q.removeClass().addClass(cssClass);
                }
            });
            if (this.params.hasOwnProperty("class")) {
                debugger;
                this.get$C().removeClass().addClass(this.params["class"]);
            }
            this._loadAnimate(false);
            var self = this;
            if (this._compiledTpl == null) {
                $.ajax({url: NengLong.Mvc.Config.getTemplateFullUrl(this._templateUrl), isNLMvc: true}).success(function (tpl) {
                    this.templateHtml = tpl;
                    NengLong.Mvc.Page._controlTreeInit(self, tpl);
                }).error(function () {
                        self._compiledTpl = null;
                    });
            } else {
                if (!!this.templateHtml) {
                    NengLong.Mvc.Page._controlTreeInit(self, this.templateHtml);
                }
            }
        }
        this.init = function () {

        }
        this.render = function () {
        }
        //不能重载， 数据绑定，子模板加载，事件绑定，设置模板的viewState,触发preOnload
        this._databind = function () {

            this.get$C().html(NengLong.Mvc.Config.getTemplateEngine().render(this, this.datasource));//this._compiledTpl.render(data));
            NengLong.Mvc.Page._setControlTreeContainer(this);
            NengLong.Mvc.Page._viewEventBind(this);
        };
        this.finish = function () {
        }
        //加载结束，不能重载
        this._unload = function () {
            this._loadAnimate(true);
        }

        //当前view跳转加载另一url对应的view
        this.redirect = function (url, params) {
            NengLong.Mvc.Page.loadTemplate(this.get$C(), url, params);

        }
        //刷新view
        this.refresh = function () {
            this._viewState = 0;
            this._processState = 0;
            this._eventOrderControl();
        }

        this._value = null;
        this.setValue = function (val) {
            this._value = val
        }
        this.getValue = function () {
            return this._value;
        }

        this.setProperty = function (options) {
            if (!!options) {
                $.extend(true, this.property, options);
            }
        }
        this.getProperty = function () {
            return this.property;
        }

        this.setInitConfig = function (options) {
            if (!!options) {
                $.extend(true, this.initconfig, options);
            }
        }
        this.getInitConfig = function () {
            return this.initconfig;
        }

        this.show = function () {
            this._hidden = false;
            this.get$C().show.apply(this.get$C(), arguments);
        }
        this.hide = function () {
            this._hidden = true;
            this.get$C().hide.apply(this.get$C(), arguments);
        }

        this.find$ = function (tagId) {
            var view = this;
            var $find = NengLong.Mvc.Page._find$(view, tagId);
            $find.setForm = function (form, elAdaptor) {
                view.setForm(form, tagId, elAdaptor);
            }
            $find.getForm = function (elAdaptor) {
                return view.getForm(tagId, elAdaptor);
            }
            return $find;
        }

        this.getControlData = function ($control) {
            NengLong.Mvc.Page._viewMvcGetControlData($control);
        }
    });

    /**
     *mvc框架的控件基类，提供给控件继承
     */
    $NL.cls("Control", function () {
        this.$ = {};//view中的jquery控件集合
        this.page = NengLong.Mvc.Page;
        this.data = {};
        this.control = {};//Control中的mvc控件集合 add by gzq
        this.userControl = {};//Control中的用户控件集合
        this.property = {};//Control中的配置属性property集合 add by gzq
        this.initconfig = {};//Control中的配置属性initconfig集合,约定只能用控件init初始化时使用，其他时刻禁用 add by gzq
        this.tmplScript = [];//Control中的自定义模板嵌套块集合 add by gzq
        this.templateHtml = "";

        //私有变量
        this._parentView = null;//父view
        this._childrenViews = [];//子view列表
        this._viewState = 0; //0初始化(PreInit) 1 (Init)， 2(render) 3(databind) 4(finish) 5（unload）（加载完成）
        this._processState = 0; //0等待， 1处理中，2处理完成，等待下一步。
        this.__taskCount = 0; //正在处理的任务数量计数器
        this._$container = null;//容器，即模板填充的jquery对象
        this._mvcId = null;//系统产生的控件的唯一id
        this.set$C = function ($container) {
            this._$container = $container;
            this._$container.data("control", this);
        }
        this.get$C = function () {
            return this._$container;
        }

        this.getParentView = function () {
            return this._parentView;
        }
        this.getChildrenView = function (viewId) {
            if (!!viewId) {
                for (var i = 0; i < this._childrenViews.length; i++) {
                    if (this._childrenViews[i]._viewId == viewId) return this._childrenViews[i];
                }
            } else {
                if (this._childrenViews.length > 0)
                    return  this._childrenViews[0];
            }

            return null
        }

        this._compiledTpl = null;//编译后的模板

        this._value = null;
        this.setValue = function (val) {
            this._value = val
        }
        this.getValue = function () {
            if (!this._value) {
                if (!!this._parentView) {
                    //data-bindName 数据绑定名
                    var ds = this._parentView.getValue();
                    var bindName = $(this.containHtml).attr("data-bindName");
                    if (isUndefined(bindName)) {
                        return ds;
                    } else {
                        if (ds.hasOwnProperty(bindName)) {
                            return ds[bindName];
                        } else {
                            return null;
                        }
                    }
                }
            }
            return this._value;
        }

        this._form = null;
        this.getF = function () {
            return this._form;
        }
        this.setF = function (val) {
            this._form = val;
        }

        this.setProperty = function (options) {
            if (!!options) {
                $.extend(true, this.property, options);
            }
        }
        this.getProperty = function () {
            return this.property;
        }

        this.setInitConfig = function (options) {
            if (!!options) {
                $.extend(true, this.initconfig, options);
            }
        }
        this.getInitConfig = function () {
            return this.initconfig;
        }

        this._taskPush = function () {
            if (this.__taskCount == 0) {
                this._processState = 1;
            }
            this.__taskCount++;
            $NL.log.i(this.className + " 的__taskCount+1 = " + this.__taskCount + ", viewState = " + this._viewState);
//            if (this._parentView != null) {
//                this._parentView._taskPush();
//            }
        }
        this._taskPop = function () {
            this.__taskCount--;
            $NL.log.i(this.className + " 的__taskCount-1 = " + this.__taskCount + ", viewState = " + this._viewState);
            if (this.__taskCount == 0) {
                var self = this;
                if (this._parentView == null || this._parentView._viewState == 5) {
                    //setTimeout(function () {
                    self._processState = 2;
                    self._eventOrderControl();
                    //}, 1);
                }
                else {
                    //setTimeout(function () {
                    self._processState = 2;
                    self._parentView._eventOrderControl();
                    //}, 1);
                }
            }
//            if (this._parentView != null) {
//                this._parentView._taskPop();
//            }
        }
        this._eventOrderControl = function () {
            NengLong.Mvc.Page._liftEventOrderCtrl(this);

        }
        this._preInit = function () {
            NengLong.Mvc.Page._controlTreeInit(this, this.templateHtml);
        }
        this.init = function () {
        }

        this.render = function () {
        };
        this._databind = function () {
            if (!isNull(this._compiledTpl)) {
                this.get$C().html(NengLong.Mvc.Config.getTemplateEngine().render(this, this.getValue()));
                NengLong.Mvc.Page._setControlTreeContainer(this);
                NengLong.Mvc.Page._viewEventBind(this);
            }
        }
        this.finish = function () {
        }
        //加载结束
        this._unload = function () {
        }

        this.getControlData = function ($control) {
            NengLong.Mvc.Page._viewMvcGetControlData($control);
        }
        //刷新模板
        this.refreshTemplate = function () {
//            if(this._parentView !=null){
//                this._parentView.__taskCount -= this.__taskCount;
//            }
//            this.__taskCount=0;
            this._preInit();
        }
        //刷新view
        this.refresh = function () {
//            if(this._parentView !=null){
//                this._parentView.__taskCount -= this.__taskCount;
//            }
//            this.__taskCount=0;
            this._viewState = 0;
            this._processState = 0;
            this._eventOrderControl();
        }

        //刷新数据
//        this.refreshData = function () {
//            this._viewState = 2;
//            this._processState = 0;
//            this._eventOrderControl();
//        }

        this.show = function () {
            if (this.get$C()) {
                this.get$C().show();
            }
        }
        this.hide = function () {
            if (this.get$C()) {
                this.get$C().hide();
            }
        }
        this.find$ = function (tagId) {
            return NengLong.Mvc.Page._find$(this, tagId);
        }

    });

    /**
     *用户控件基类，提供给用户控件继承
     */
    $NL.cls("UserControl", function () {
        $.extend(this, NengLong.Mvc.Page.Extend.viewBase);
        this.$ = {};//Control中的jquery控件集合
        this.page = NengLong.Mvc.Page;
        this.control = {};
        this.userControl = {};//Control中的用户控件集合
        this.property = {};//Control中的配置属性property集合 add by gzq
        this.initconfig = {};//Control中的配置属性initconfig集合,约定只能用控件init初始化时使用，其他时刻禁用 add by gzq
        this.tmplScript = [];//Control中的自定义模板嵌套块集合 add by gzq
        this.model = null;
        this.data = {};
        this.templateHtml = "";
        this.datasource = null;

        //私有变量
        this._parentView = null;//父view
        this._childrenViews = [];//子view列表
        this._viewState = 0; //0初始化(PreInit) 1 (Init)， 2(render) 3(databind) 4(finish) 5（unload）（加载完成）
        this._processState = 0; //0等待， 1处理中，2处理完成，等待下一步。
        this.__taskCount = 0; //正在处理的任务数量计数器
        this._$container = null;//容器，即模板填充的jquery对象
        this._mvcId = null;//系统产生的控件的唯一id
        this.set$C = function ($container) {
            this._$container = $container;
            this._$container.data("control", this);
        }
        this.get$C = function () {
            return this._$container;
        }
        this.getParentView = function () {
            return this._parentView;
        }
        this.getChildrenView = function (viewId) {
            if (!!viewId) {
                for (var i = 0; i < this._childrenViews.length; i++) {
                    if (this._childrenViews[i]._viewId == viewId) return this._childrenViews[i];
                }
            } else {
                if (this._childrenViews.length > 0)
                    return  this._childrenViews[0];
            }

            return null
        }

        this._compiledTpl = null;//编译后的模板
        //值属性读写器
        this._value = null;
        this.setValue = function (val) {
            this._value = val
        }
        this.getValue = function () {
            return this._value;
        }

        this._form = null;
        this.getF = function () {
            return this._form;
        }
        this.setF = function (val) {
            this._form = val;
        }

        this.setProperty = function (options) {
            if (!!options) {
                $.extend(true, this.property, options);
            }
        }
        this.getProperty = function () {
            return this.property;
        }
        this.setInitConfig = function (options) {
            if (!!options) {
                $.extend(true, this.initconfig, options);
            }
        }
        this.getInitConfig = function () {
            return this.initconfig;
        }

        this._taskPush = function () {
            if (this.__taskCount == 0) {
                this._processState = 1;
            }
            this.__taskCount++;
            $NL.log.i(this.className + " 的__taskCount+1 = " + this.__taskCount + ", viewState = " + this._viewState);
//            if (this._parentView != null) {
//                this._parentView._taskPush();
//            }
        }
        this._taskPop = function () {
            this.__taskCount--;
            $NL.log.i(this.className + " 的__taskCount-1 = " + this.__taskCount + ", viewState = " + this._viewState);

            if (this.__taskCount == 0) {
                var self = this;
                if (this._parentView == null || this._parentView._viewState == 5) {
                    //setTimeout(function () {
                    self._processState = 2;
                    self._eventOrderControl();
                    //}, 1);
                }
                else {
                    //setTimeout(function () {
                    self._processState = 2;
                    self._parentView._eventOrderControl();
                    //}, 1);
                }
            }
//            if (this._parentView != null) {
//                this._parentView._taskPop();
//            }
        }
        this._eventOrderControl = function () {
            NengLong.Mvc.Page._liftEventOrderCtrl(this);
        }
        this._preInit = function () {
            var self = this;
            //NengLong.Mvc.Page._viewMvcControlPropertyBind(this);
            if (this._compiledTpl == null) {
                $.ajax({url: NengLong.Mvc.Config.getUserControlTemplatFullUrl(this.className), isNLMvc: true}).success(function (tpl) {
                    self.templateHtml = tpl;
                    NengLong.Mvc.Page._controlTreeInit(self, self.templateHtml);
                }).error(function () {
                        this._compiledTpl = null;
                        $NL.log.e("加载控件失败，控件类名：" + self.className);
                    });
            } else {
                NengLong.Mvc.Page._controlTreeInit(self, self.templateHtml);
            }
        }
        this.init = function () {
        }
        //render函数，提供给具体的view重载，函数中需执行this.databind
        this.render = function () {
        };
        this._databind = function () {
            if (!isNull(this._compiledTpl)) {
                this.get$C().html(NengLong.Mvc.Config.getTemplateEngine().render(this, this.datasource))
                NengLong.Mvc.Page._setControlTreeContainer(this);
                NengLong.Mvc.Page._viewEventBind(this);
            }
        }
        this.finish = function () {
        }

        //加载结束
        this._unload = function () {
        }

        this.getControlData = function ($control) {
            NengLong.Mvc.Page._viewMvcGetControlData($control);
        }
        //刷新模板
        this.refreshTemplate = function () {
//            if(this._parentView !=null){
//                this._parentView.__taskCount -= this.__taskCount;
//            }
//            this.__taskCount=0;
            this._preInit();
        }
        //刷新view
        this.refresh = function () {
//            if(this._parentView !=null){
//                this._parentView.__taskCount -= this.__taskCount;
//            }
//            this.__taskCount=0;
            this._viewState = 0;
            this._processState = 0;
            this._eventOrderControl();
        }

        //刷新数据
//        this.refreshData = function () {
//            this._viewState = 2;
//            this._processState = 0;
//            this._eventOrderControl();
//        }

        this.show = function () {
            if (this.get$C()) {
                this.get$C().show();
            }
        }
        this.hide = function () {
            if (this.get$C()) {
                this.get$C().hide();
            }
        }
        this.find$ = function (tagId) {
            return NengLong.Mvc.Page._find$(this, tagId);
        }
    });
});